<?php

namespace app\model;

use think\facade\Db;
use think\Model;
use think\model\relation\HasMany;
use think\model\relation\HasOne;
use yly_print\YlyOpen;

class StationBasic extends Model
{
    public function addOrUpdate(): array
    {
        $param = request()->post();
        if (!empty($param['print_sn'])) {
            $count = $this->where('print_sn', $param['print_sn'])->when(!empty($param['id']), function ($query) use ($param) {
                $query->where('id', '<>', $param['id']);
            })->count();
            if ($count > 0) throw new \Exception("重复绑定打印机！");
        }
        $det = [];
        if (!empty($param['id'])) {
            $det = $this->find($param['id']);
            if (!empty($det)) $det = $det->toArray();
        }
        $mode = app(StationOil::class);
        $oilLst = $param['oilData'];
        unset($param['oilData']);
        $deleteOil = [];
        if (!empty($param['id'])) {
            $oil = $mode->where('station_id', $param['id'])->column("id");
            $deleteOil = array_diff($oil, array_column($oilLst, "id"));
        }
        if (!empty($param['account'])) {
            $count = $this->where('account', $param['account'])->when(!empty($param['id']), function ($query) use ($param) {
                $query->where('id', '<>', $param['id']);
            })->count();
            if ($count > 0) throw new \Exception("油站账号已存在，请重新输入！");
        }
        if (!empty($param['password'])) {
            $password = setPassword($param['password']);
            $param['password'] = $password['password'];
            $param['token'] = $password['token'];
        } else unset($param['password']);
        if (is_numeric($param['lng']) && is_numeric($param['lat'])) {
            $param['lng_lat'] = Db::raw("ST_GeomFromText('POINT({$param['lng']} {$param['lat']})')");;
        }
        if (!empty($param['print_sn']) && (empty($param['id']) || empty($det['print_sn']) || $det['print_sn'] != $param['print_sn'])) {
            //綁定打印機
            app(YlyOpen::class)->getTokenBySecret($param['print_sn'], $param['print_key']);
        }
        $deleteOil = array_values(array_unique($deleteOil));
        $this->startTrans();
        $this->exists(!empty($param['id']))->save($param);
        $data = $this->toArray();
        $oil = array_map(function ($item) use ($data) {
            $def_tip = $item['def_tip'] ?? "";
            unset($item['def_tip'], $item['gun_items']);
            $def_tip = explode("#", $def_tip);
            $item['station_id'] = $data['id'];
            $item['oil_name'] = $def_tip[0] . "#";
            $item['oil'] = $def_tip[0];
            $item['offic_price'] = $def_tip[1] ?? 0;
            $item['gun_price'] = $def_tip[2] ?? $def_tip[1] ?? 0;
            $item['gun_discount'] = round($item['offic_price'] - $item['gun_price'], 2);
            return $item;
        }, $oilLst);
        if (!empty($deleteOil)) {
            $mode->whereIn('id', $deleteOil)->delete();
        }
        $mode->saveAll($oil);
        $this->commit();
        if (empty($data['number'])) {
            //id填充4个0
            $number = $data['id'];
            if (strlen($number) < 10) $number = "GL_0000$number";
            elseif (strlen($number) < 100) $number = "GL_000$number";
            elseif (strlen($number) < 1000) $number = "GL_00$number";
            elseif (strlen($number) < 10000) $number = "GL_0$number";
            else $number = "GL_$number";
            $this->where('id', $data['id'])->update(['number' => $number]);
        }
        return $data;
    }

    public function merchant(): HasOne
    {
        return $this->hasOne(Merchant::class, 'id', 'mer_id');
    }

    public function oil(): HasMany
    {
        return $this->hasMany(StationOil::class, 'station_id', 'id');
    }

    public function lst(): array
    {
        $param = request()->param();
        $data = $this->with(['merchant'])->when(!empty($param['name']), function ($query) use ($param) {
            $query->where('name|number', 'like', "%{$param['name']}%");
        })->order('create_time', 'desc')->paginate([
            'list_rows' => $param['size'] ?? 30,
            'page' => $param['page'] ?? 1,
        ])->toArray();
        $data['data'] = array_map(function ($item) {
            $item['qrcode'] = station_qrcode($item['name'], $item['id']);
            return $item;
        }, $data['data']);
        return pageData($data);
    }

    public function detail(): array
    {
        $id = request()->param('id');
        $lat = request()->param('lat');
        $lng = request()->param('lng');
        $field = ['*'];
        if (!empty($lat) && !empty($lng) && is_numeric($lat) && is_numeric($lng)) {
            $distanceExpression = "ST_Distance_Sphere(lng_lat, ST_GeomFromText('POINT($lng $lat)'))";
            $field[] = Db::raw("{$distanceExpression} AS distance");
        }
        $data = $this->where('id', $id)->field($field)->find();
        if (empty($data)) throw new \Exception("油站不存在");
        $data = $data->toArray();
        unset($data['password']);
        $oilData = app(StationOil::class)->where(['station_id' => $id])->order(['oil' => 'asc'])->select()->toArray();
        $prices = ["sat_price", "mon_price", "tue_price", "wed_price", "thu_price", "fri_price", "sat_price"][date("w")];
        $defPrice = $data[$prices] > 0 ? $data[$prices] : $data['default_price'];
        $type = $data['rate_unit'];
        $oilData = array_map(function ($item) use ($type, $prices, $defPrice) {
            $item['def_tip'] = $item['oil'] . "#" . $item['offic_price'] . "#" . $item['gun_price'];
            $item['gun_items'] = '';
            return $this->extracted($item, $prices, $type, $defPrice);
        }, $oilData);
        $data['oilData'] = $oilData;
        $data['distance'] = (float)bcdiv($data['distance'] ?? 0, 1000, 2);
        return $data;
    }

    public function series()
    {
        $id = request()->post('id');
        $ser_price = request()->post('ser_price');
        return $this->where('id', $id)->update(['ser_price' => $ser_price]);
    }

    public function state()
    {
        $id = request()->post("id");
        $data = $this->find($id);
        if (empty($data)) throw new \Exception("油站不存在");
        return $this->where('id', $id)->update(['state' => $data['state'] == 1 ? 2 : 1]);
    }

    public function city()
    {
        return $this->group('city_code')->column("city_code `key`,city `label`");
    }

    public function userStation(): array
    {
        $param = request()->param();
        $field = [
            '*'
        ];
        $location = false;
        $distanceExpression = null;
        if ((!empty($param['lat']) && !empty($param['lng'])) && (is_numeric($param['lat']) && is_numeric($param['lng']))) {
            // 构建距离表达式
            $distanceExpression = "ST_Distance_Sphere(lng_lat, ST_GeomFromText('POINT({$param['lng']} {$param['lat']})'))";
            $field[] = Db::raw("{$distanceExpression} AS distance");
            $location = true;
        }

        $radius = 5000;
        if (!empty($param['distance']))
            $radius = $param['distance'] != 'all' ? $param['distance'] * 1000 : 0;
        $radiusCondition = null;
        if ($location && isset($radius) && $radius > 0) {
            $radiusCondition = ("$distanceExpression < {$radius}");
        }
        $order = $location ? "distance ASC" : 'create_time DESC';
        if ($param['sort'] == 1) {
            $order = "distance ASC";
        } elseif ($param['sort'] == 2) {
            $order = "distance DESC";
        }
        $data = $this->with(['oil' => function ($query) use ($param) {
            $query->when(!empty($param['gas']) && $param['gas'] != '全部', function ($q) use ($param) {
                $q->where('oil_name', $param['gas']);
            });
        }])->when(!empty($param['name']), function ($query) use ($param) {
            $query->where('name|number', 'like', "%{$param['name']}%");
        })->when(!empty($radiusCondition), function ($query) use ($radiusCondition) {
            $query->whereRaw($radiusCondition);
        })->when(!empty($param['gas']) && $param['gas'] != '全部', function ($query) use ($param) {
            //$station_id = app(StationOil::class)->where('oil_name', $param['gas'])->column('station_id');
            $id = StationOil::where('oil_name', $param['gas'])->column('station_id');
            $query->whereIn('id', $id);
        })->where('state', 1)->field($field)->order($order)->paginate([
            'list_rows' => 15,
            'page' => $param['page'] ?? 1,
        ])->toArray();
        $prices = ["sat_price", "mon_price", "tue_price", "wed_price", "thu_price", "fri_price", "sat_price"][date("w")];
//        $price =
        $data['data'] = array_map(function ($item) use ($prices) {
            if (empty($item['oil'])) return null;
            $rate = $item['rate_unit'];
            $def = $item[$prices] > 0 ? $item[$prices] : $item['default_price']; //默认优惠金额
            $item['oil'] = array_map(function ($oil) use ($def, $prices, $rate) {
                return $this->extracted($oil, $prices, $rate, $def);
            }, $item['oil']);
            $item['distance'] = (float)bcdiv($item['distance'] ?? 0, 1000, 2);
            if (!empty($item['oil'])) {
                $item['min_price'] = min(array_column($item['oil'], 'discount_price'));
                $item['offic_price'] = min(array_column($item['oil'], 'offic_price'));
                $item['gun_price'] = min(array_column($item['oil'], 'gun_price'));
            }
            return $item;
        }, $data['data']);
        $data['data'] = array_values(array_filter($data['data']));
        return pageData($data);
    }

    /**
     * @param mixed $oil
     * @param string $prices
     * @param mixed $rate
     * @param mixed $def
     * @return mixed
     */
    public function extracted(mixed $oil, string $prices, mixed $rate, mixed $def): mixed
    {
//        $type = $oil[$prices] > 0 || $oil['default_price'] > 0 ? $oil['rate_unit'] : $rate;
//        $mon = $oil[$prices] > 0 ? $oil[$prices] : ($oil['default_price'] > 0 ? $oil['default_price'] : $def);
        //获取优惠价格
        $oil['discount_price'] = mathDiscount($rate, $def, $oil['gun_price']);
        return $oil;
    }
}
